package components
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	flash.events.Event;
	/**
	 * @author perry
	 */
	public class ECGReader extends ECGReaderView
	{
		public static const NAME:String 			= "ECGReader";
		public static const COMPLETE:String 		= NAME + "Complete";
		
		private var SCALEX:Number 			= 80;
		private var SCALEY:Number 			= 50;
		private var ACCURACY:Number 		= 3;
		private var DEMO:Boolean			= false;
		
		private var colorLine:Number		= 0xFFFFFFFF;

		private var path:String;
		
		private var ecgDataLoader:ECGDataLoader;
		private var plotData:Vector.<ECGSignal>;
		private var currentSignal:ECGSignal;
		
		private var maxIndex:int;
		private var totalTime:Number;
		private var halfStageWidth:Number;
		private var halfStageHeigth:Number;
		
		private var higherMV:Number = 0;
		private var lowerMV:Number = 0;
		
		private var minIndex:int = 0;
		
		private var bmpCanvas:Bitmap;
		private var bmpd:BitmapData;
		
		private var bounds:Rectangle;
		private var buffer:ByteArray;
		
		private var plotPoint:Number = 0;
		private var pixelOffset:Number = 0;
		
		public function ECGReader()
		{
			if( DEMO )blocker.visible = true;
			else blocker.visible = false;
		}

/**
 * PUBLIC
 */	
		public function init():void
		{
			baseline.alpha = 0.2;
			buildECGReader();
		}
		public function loadFile( pth:String ):void
		{
			path = pth;
			
			higherMV 		= 0;
			lowerMV 		= 0;
			
			secLabel.text 	= "0.0";
			beatLabel.text 	= "0";
			maxMVLabel.text = String( higherMV );
			minMVLabel.text = String( lowerMV );
			
			maxIndex 			= 0;
			minIndex 		= 0;
			plotPoint 		= 0;
			pixelOffset 	= 0;
			
			ecgDataLoader.init( path );
		}
		
		public function lock():void
		{
			this.removeEventListener(Event.ENTER_FRAME, loop );
		}
		
		public function unlock():void
		{
			this.addEventListener(Event.ENTER_FRAME, loop );
		}
		
/**
 * PRIVATE
 */
		private function buildECGReader():void
		{
			
			halfStageWidth = this.stage.stageWidth / 2;
			halfStageHeigth = this.stage.stageHeight / 2;
			
			bmpd = new BitmapData( halfStageWidth, halfStageHeigth * 2, true, 0x00ff0000 );
			bmpCanvas = new Bitmap( bmpd );
			
			bounds = new Rectangle( 0, 0, bmpCanvas.width, bmpCanvas.height );
			buffer = new ByteArray();
			buffer = bmpCanvas.bitmapData.getPixels( bounds );			
			buffer.position = 0;
			
			addChild( bmpCanvas );
			
			ecgDataLoader = new ECGDataLoader();
			ecgDataLoader.addEventListener(ECGDataLoader.DATA_LOADED, ecgDataChangedHandler );
			ecgDataLoader.addEventListener( ECGDataLoader.COMPLETE, ecgDataCompleteHandler );			
		}
		
		private function addEvents( to:String = "all" ):void
		{
			switch( to )
			{
				case "all":
				
					playBtn.buttonMode = true;
					pauseBtn.buttonMode = true;
					
					playBtn.addEventListener( MouseEvent.MOUSE_DOWN, playDownHandler );
					pauseBtn.addEventListener( MouseEvent.MOUSE_DOWN, pauseDownHandler );
					
				break;
				case "play":
				
					playBtn.buttonMode = true;
					playBtn.addEventListener( MouseEvent.MOUSE_DOWN, playDownHandler );
					
				break;
				case "pause":
				
					pauseBtn.buttonMode = true;
					pauseBtn.addEventListener( MouseEvent.MOUSE_DOWN, pauseDownHandler );
					
				break;
			}
		}
		
		private function removeEvents( to:String = "all" ):void
		{
			switch( to )
			{
				case "all":
				
					playBtn.buttonMode = false;
					pauseBtn.buttonMode = false;
					
					playBtn.removeEventListener( MouseEvent.MOUSE_DOWN, playDownHandler );
					pauseBtn.removeEventListener( MouseEvent.MOUSE_DOWN, pauseDownHandler );
					
				break;
				case "play":
				
					playBtn.buttonMode = false;
					playBtn.removeEventListener( MouseEvent.MOUSE_DOWN, playDownHandler );
					
				break;
				case "pause":
				
					pauseBtn.buttonMode = false;
					pauseBtn.removeEventListener( MouseEvent.MOUSE_DOWN, pauseDownHandler );
					
				break;
			}
		}
		
		private function paint():void
		{
			buffer.position = 0;
			bmpCanvas.bitmapData.setPixels( bounds,buffer );
			
			var i:uint;
			for( i = minIndex; i < maxIndex; i++ )
			{
				if( i + 1 >= totalTime )
					break;
				
				line( (	plotData[i].t * SCALEX ), plotData[i].mV * SCALEY,
						( plotData[i + 1].t * SCALEX ), plotData[i + 1].mV * SCALEY, 
						colorLine );
			}
			
		}
		
		private function plot( x:Number, y:Number, col:uint ):void
		{
			plotPoint = x;
			
			bmpCanvas.bitmapData.setPixel32( plotPoint - pixelOffset, y + baseline.y, col );
		}
		
		private function setToDemo():void
		{
			if( DEMO )
			{
				blocker.visible = true;
				halfStageWidth 	= 800;
				lock();
			}
			else
			{
				blocker.visible = false;
				halfStageWidth 	= stage.stageWidth / 2;
				unlock();
			}
		}

/**
 * EVENT HANDLERS
 */
		private function loop( e:Event ):void
		{
			
			if( (maxIndex + 1) >= totalTime )
			{
				lock();
				return;
			}
			
			paint();
			
			if( plotData[maxIndex].mV > higherMV ) 						higherMV = plotData[maxIndex].mV;
			if( plotData[maxIndex].mV < lowerMV ) 						lowerMV = plotData[maxIndex].mV;
			if( beatLabel.text != String( plotData[maxIndex].beat ) ) 	heartIcon.play();
			
			beatLabel.text 		= String( plotData[maxIndex].beat );
			secLabel.text 		= String( plotData[maxIndex].t );
			maxMVLabel.text 	= String( higherMV );
			minMVLabel.text 	= String( lowerMV );
			
			if( plotPoint > halfStageWidth )
			{			
				pixelOffset = plotPoint - halfStageWidth;
				
				minIndex++;
			}
			else
			{
				plotPoint = 0;
			}
			
			maxIndex++;
		}

		private function ecgDataCompleteHandler( e:Event ):void
		{
			plotData = ecgDataLoader.precision( ACCURACY );
			currentSignal = plotData[0];
			
			totalTime = plotData.length;			
			
			setToDemo();
			
			if( !DEMO )
				playDownHandler( null );
			else
			{
				var i:uint;
				for( i = 0; i < totalTime; i++ )
				{
					line( 	plotData[i].t, plotData[i].mV,
							plotData[i + 1].t, plotData[i + 1].mV,
							colorLine );
							
					if( plotData[i + 1].t > halfStageWidth )
						break;
				}
			}
			
			dispatchEvent( new Event( COMPLETE ) );
		}
		
		private function ecgDataChangedHandler( e:Event ):void
		{
			
		}

		private function playDownHandler( e:MouseEvent ):void
		{			
			playBtn.gotoAndStop( 2 );
			pauseBtn.gotoAndStop( 1 );
			
			removeEvents( "play" );
			addEvents( "pause" );
			
			unlock();
		}

		private function pauseDownHandler( e:MouseEvent ):void
		{			
			playBtn.gotoAndStop( 1 );
			pauseBtn.gotoAndStop( 2 );
			
			removeEvents( "pause" );
			addEvents( "play" );
			
			lock();
		}

/**
 * GETTERS / SETTERS
 */
		public function get demo():Boolean
		{
			return DEMO;
		}
		public function set demo( bool:Boolean ):void
		{
			DEMO = bool;
			
			setToDemo();
		}
		
/**
 * ALGORITHMS
 */
/**
 * 
 * raster line (brezanham alghorithm)
 * @param c Number
 * @param x0 int
 * @param x1 int
 * @param y0 int
 * @param y1 int
 * 
 * @return void
 * 
 */
		private function line( x0:int, y0:int, x1:int, y1:int, c:Number=0x000460 ):void
		{
			var Dx:int = x1 - x0;
			var Dy:int = y1 - y0;
					 
			var steep:Boolean = Math.abs( Dy ) >= Math.abs( Dx );
		
			if( steep )
			{
				var tmp:Number = x0;
				x0 = y0;
				y0 = tmp;
						
				tmp = x1;
				x1  = y1;
				y1  = tmp;
				//x1^= y1 ^= x0 ^= y0
						
				Dx = x1 - x0;
				Dy = y1 - y0;
			}
					
			var xstep:int = 1;
		
			if( Dx < 0 )
			{
				xstep = -1;
				Dx = -Dx;
			}
					
			var ystep:int = 1;
			if( Dy < 0 )
			{
				ystep = -1;
				Dy = -Dy;
			}
					
			var TwoDy:Number = 2 * Dy;
			var TwoDyTwoDx:Number = TwoDy - 2*Dx;
			var E:int = TwoDy - Dx;
					
			var Y:int = y0;
			
			var xDraw:int;
			var yDraw:int;
					
			for( var X:int = x0; X != x1; X += xstep )
			{
				if ( steep )
				{
							
					xDraw = Y;
					yDraw = X;
							
				}
				else
				{
					xDraw = X;
					yDraw = Y;
				}
		
				plot( xDraw, yDraw, c ); //PLOT THE LINE DOT ON YOUR BITMAP DATA
				
				// NEXT
		
				if( E > 0 )
				{
					E += TwoDyTwoDx; //E += 2*Dy - 2*Dx;
					Y = Y + ystep;
				}
				else
				{
					E += TwoDy; //E += 2*Dy;
				}
			}
		}

	}
}
